package olegroshka.src.com.bofa.olegroshka.report;

import java.io.PrintStream;
import java.util.HashMap;
import java.util.Map;

import javax.sound.midi.Sequence;

import olegroshka.src.com.bofa.olegroshka.aggregators.Aggregator;
import olegroshka.src.com.bofa.olegroshka.datasource.DataSource;
import olegroshka.src.com.bofa.olegroshka.datasource.FilteringDataSource;
import olegroshka.src.com.bofa.olegroshka.datasource.FlatFileDataSource;
import olegroshka.src.com.bofa.olegroshka.datasource.GroupByDataSource;
import olegroshka.src.com.bofa.olegroshka.datasource.JoinDataSource;
import olegroshka.src.com.bofa.olegroshka.datasource.ParsingDataSource;
import olegroshka.src.com.bofa.olegroshka.datasource.ReportDataSource;
import olegroshka.src.com.bofa.olegroshka.datasource.SequentialJoinDataSource;
import olegroshka.src.com.bofa.olegroshka.datasource.SortingDataSource;
import olegroshka.src.com.bofa.olegroshka.datasource.TransformingDataSource;
import olegroshka.src.com.bofa.olegroshka.decorator.Transformation;
import olegroshka.src.com.bofa.olegroshka.filter.Filter;
import olegroshka.src.com.bofa.olegroshka.format.RecordFormatter;
import olegroshka.src.com.bofa.olegroshka.parsers.Parser;
import olegroshka.src.com.bofa.olegroshka.sort.SortCriteria;

public class ReportGeneratorBuilder {
	
	private final Map<String, DataSource> dataSources = 
			new HashMap<String, DataSource>();
	
	private Object[] headers;
	private Aggregator[] totalRules;
	private RecordFormatter[] headerFormatters;
	private RecordFormatter recordFormatter;
	private RecordFormatter[] footerFormatters;
	private PrintStream[] printStreams;
	
	public ReportGeneratorBuilder in(
			String name,
			String filePath, 
			String delimiter) {
		dataSources.put(name, new FlatFileDataSource(filePath, delimiter));
		return this;
	}

	public ReportGeneratorBuilder filter(
			String name,
			Filter... filters) {
		DataSource dataSource = getDataSource(name);
		
		dataSources.put(name, new FilteringDataSource(dataSource, filters));
		
		return this;
	}
	
	public ReportGeneratorBuilder parse(
			String name,
			Parser... parsers) {
		DataSource dataSource = getDataSource(name);
		
		dataSources.put(name, new ParsingDataSource(dataSource, parsers));
		
		return this;
	}

	private DataSource getDataSource(String name) {
		DataSource dataSource = dataSources.get(name);
		if( dataSource == null ) {
			throw new IllegalArgumentException("Can't find data source: " + name);
		}
		return dataSource;
	}

	public ReportGeneratorBuilder group(
			String name, 
			int column, 
			Aggregator... aggregators) {
		DataSource dataSource = getDataSource(name);
		dataSources.put(name, new GroupByDataSource(dataSource, column, aggregators));
		return this;
	}
	
	public ReportGeneratorBuilder join(
			String name, 
			String leftName, 
			String rightName, 
			int leftColumn, 
			int rightColumn,
			int leftRecordLength,
			int rightRecordLength) {
		DataSource leftDataSource = getDataSource(leftName);
		DataSource rightDataSource = getDataSource(rightName);
		dataSources.put(name, 
				new JoinDataSource(leftDataSource, rightDataSource, 
						leftColumn, rightColumn, leftRecordLength, rightRecordLength));
		return this;
	}
	
	public ReportGeneratorBuilder decorate(
			String name, 
			Transformation... transformations) {
		DataSource dataSource = getDataSource(name);
		dataSources.put(name, new TransformingDataSource(dataSource, transformations));
		
		return this;
	}
	
	public ReportGeneratorBuilder sort(
			String name, 
			SortCriteria... sortCriteria) {
		DataSource dataSource = getDataSource(name);
		dataSources.put(name, new SortingDataSource(dataSource, sortCriteria));
		return this;
	}
	
	public ReportGeneratorBuilder headerData(Object... headers) {
		this.headers = headers;
		return this;
	}
	
	public ReportGeneratorBuilder totals(Aggregator... totalRules) {
		this.totalRules = totalRules;
		return this;
	}
	
	public ReportGeneratorBuilder headerFormatters(RecordFormatter... headerFormatters) {
		this.headerFormatters = headerFormatters;
		return this;
	}
	
	public ReportGeneratorBuilder recordFormatters(RecordFormatter recordFormatters) {
		this.recordFormatter = recordFormatters;
		return this;
	}
	
	public ReportGeneratorBuilder footerFormatters(RecordFormatter... footerFormatters) {
		this.footerFormatters = footerFormatters;
		return this;
	}
	
	public ReportGeneratorBuilder printTo(PrintStream... printStreams) {
		this.printStreams = printStreams;
		return this;
	}
	
	/**
	 * Creates report generator.
	 * 
	 * @param name data source name
	 * @return report generator
	 */
	public ReportGenerator build(String name) {
		if( printStreams == null || printStreams.length == 0 ) {
			throw new IllegalArgumentException("Print streams can't be null or empty.");
		 } //etc..
		
		DataSource dataSource = getDataSource(name);
		SimpleReportPrinter reportWriter = 
				new SimpleReportPrinter(
						printStreams, 
						headerFormatters, 
						recordFormatter, 
						footerFormatters);
		
		ReportDataSource reportDataSource = 
				new ReportDataSource(headers, dataSource, totalRules);

		return new ReportGenerator(reportDataSource, reportWriter);
	}
	
}
